package com.example.jimuyutabletcontrol.activity;

import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.example.jimuyutabletcontrol.R;
import com.example.jimuyutabletcontrol.network.udp.UdpMessageHandle;
import com.example.jimuyutabletcontrol.network.udp.UdpMessageType;
import com.example.jimuyutabletcontrol.network.udp.UdpSocket;
import com.example.jimuyutabletcontrol.pulltorefresh.PullListView;
import com.example.jimuyutabletcontrol.pulltorefresh.PullToRefreshLayout;
import com.example.jimuyutabletcontrol.adapter.pulltorefreshadapter.ListAdapter;
import com.example.jimuyutabletcontrol.utils.MsgType;

import java.util.ArrayList;
import java.util.List;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

public class SelectAUVFixMapActivity extends AppCompatActivity implements
        PullToRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener, View.OnClickListener {
    private PullToRefreshLayout mRefreshLayout;
    private PullListView mPullListView;

    private List<String> mStrings;
    private ListAdapter mAdapter;

    private static SelectAUVFixMapActivity self;
    private UdpMessageHandle handle;

    public static SelectAUVFixMapActivity getInstance() {
        return self;
    }

    private Point[] pentagonVertices;
    private Button[] buttons;
    private int width;
    private int radius;
    private int startPositionX;
    private int startPositionY;
    private int whichAnimation;
    private int NUM_OF_SIDES;
    private int[] enterDelay = {80, 120, 160, 40, 0, 200, 240};
    private int[] exitDelay = {80, 40, 0, 120, 160, 200, 240};
    private String[] content = {"制作任务", "发送任务", "实地测绘"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.selectauvfixmapinterface_pull_to_refresh);
        self = this;

        Toolbar toolbar = findViewById(R.id.toolbarfixmap);
        toolbar.setTitle("AUV导航任务修改");
        setSupportActionBar(toolbar);

        mRefreshLayout = findViewById(R.id.pullToRefreshLayoutfixmap);
        mPullListView = findViewById(R.id.pullListViewfixmap);
        mStrings = new ArrayList<>();

        if (toolbar != null) {
            toolbar.setOnMenuItemClickListener(this);
        }
        mRefreshLayout.setOnRefreshListener(this);
        mAdapter = new ListAdapter(this, mStrings, 2);
        mPullListView.setAdapter(mAdapter);
        mPullListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                if (mPullListView.getItemAtPosition(position) != null) {
                    Intent intent = new Intent(SelectAUVFixMapActivity.this, FixTaskMapActivity.class);
                    intent.putExtra("IMEI", mPullListView.getItemAtPosition(position).toString());
                    startActivity(intent);
                }
            }
        });
        prepareFloatButton();
        setListeners();
    }

    private void setListeners() {
        handle = new UdpMessageHandle(UdpMessageType.IMEI, this::updateListData);
        UdpSocket.getInstance().setMessageCallback(handle);
    }


    @Override
    public void onClick(View view) {
        Intent intent = null;
        switch ((int) view.getTag()) {
            case 0:
                intent = new Intent(SelectAUVFixMapActivity.this, SelectAUVMakeMapActivity.class);
                startActivity(intent);
                finish();
                break;
            case 1:
                intent = new Intent(SelectAUVFixMapActivity.this, SelectAUVSendMapActivity.class);
                startActivity(intent);
                finish();
                break;
            case 2:
                intent = new Intent(SelectAUVFixMapActivity.this, MappingActivity.class);
                startActivity(intent);
                finish();
                break;
        }
    }

    @Override
    public void onRefresh(PullToRefreshLayout pullToRefreshLayout) {
        UdpSocket.getInstance().sendMessage("INSTANTIMEI");

        mRefreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                mRefreshLayout.refreshFinish(true);
                updateListDataToAdapter();
            }
        }, 2000);
    }

    @Override
    public void onLoadMore(PullToRefreshLayout pullToRefreshLayout) {
        UdpSocket.getInstance().sendMessage("INSTANTIMEI");

        mRefreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                mRefreshLayout.loadMoreFinish(true);
                updateListDataToAdapter();
            }
        }, 2000);
    }

    private void updateListDataToAdapter() {
        if (mAdapter == null) {
            mAdapter = new ListAdapter(this, mStrings, 2);
            mPullListView.setAdapter(mAdapter);
        } else {
            mAdapter.updateListView(mStrings);
        }
    }

    private void updateListData(String message) {
        runOnUiThread(() -> {
            String[] contents = message.split(",");
            int length = contents.length;
            for (int i = 1; i < length; i++) {
                if (!mStrings.contains(contents[i])) {
                    mStrings.add(contents[i]);
                }
            }
        });
    }

    public void sendMsgToMainThread(int what, String obj) {
        Message message = mHandler.obtainMessage();
        message.what = what;
        message.obj = obj;
        mHandler.sendMessage(message);
    }

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MsgType.AUVFIXMAPREFRESH:
                    updateListData(msg.obj.toString());
                    break;
            }
            super.handleMessage(msg);
        }
    };

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.selectauvfixmapinterface_menu, menu);
        return true;
    }

    @Override
    public boolean onMenuItemClick(MenuItem menuItem) {
        if (menuItem.getItemId() == R.id.auvfixmap_clear) {
            if (mStrings != null) {
                mStrings.clear();
                updateListDataToAdapter();

                return true;
            }
        } else if (menuItem.getItemId() == R.id.send_fixmap) {
            if (whichAnimation == 0) {
                /**
                 * Getting the center point of floating action button
                 *  to set start point of buttons
                 */
                startPositionX = 2600;
                startPositionY = 0;

                for (Button button : buttons) {
                    button.setX(startPositionX);
                    button.setY(startPositionY);
                    button.setVisibility(View.VISIBLE);
                }
                for (int i = 0; i < buttons.length; i++) {
                    playEnterAnimation(buttons[i], i);
                }
                whichAnimation = 1;
            } else {
                for (int i = 0; i < buttons.length; i++) {
                    playExitAnimation(buttons[i], i);
                }
                whichAnimation = 0;
            }
            return true;
        }
        return false;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != handle) {
            UdpSocket.getInstance().removeMessageCallback(handle);
            handle = null;
        }
        self = null;
    }

    private void prepareFloatButton() {
        startPositionX = 0;
        startPositionY = 0;
        whichAnimation = 0;
        NUM_OF_SIDES = 3;
        width = 200;
        radius = 200;

        calculatePentagonVertices(radius, 11);
    }

    private void calculatePentagonVertices(int radius, int rotation) {

        pentagonVertices = new Point[NUM_OF_SIDES];

        /**
         * Calculating the center of pentagon
         */
        Display display = getWindowManager().getDefaultDisplay();
        int centerX = display.getWidth() / 2;
        int centerY = display.getHeight() / 2;

        /**
         * Calculating the coordinates of vertices of pentagon
         */
        for (int i = 0; i < NUM_OF_SIDES; i++) {
            pentagonVertices[i] = new Point((int) (radius * Math.cos(rotation + i * 2 * Math.PI / NUM_OF_SIDES)) + centerX,
                    (int) (radius * Math.sin(rotation + i * 2 * Math.PI / NUM_OF_SIDES)) + centerY - 100);
        }

        buttons = new Button[pentagonVertices.length];

        for (int i = 0; i < buttons.length; i++) {
            //Adding button at (0,0) coordinates and setting their visibility to zero
            buttons[i] = new Button(SelectAUVFixMapActivity.this);
            buttons[i].setLayoutParams(new RelativeLayout.LayoutParams(100, 100));
            buttons[i].setX(0);
            buttons[i].setY(0);
            buttons[i].setTag(i);
            buttons[i].setOnClickListener(this);
            buttons[i].setVisibility(View.INVISIBLE);
            buttons[i].setBackgroundResource(R.drawable.circular_background);
            buttons[i].setTextColor(Color.DKGRAY);
            buttons[i].setText(content[i]);
            buttons[i].setTextSize(14);
            /**
             * Adding those buttons in acitvities layout
             */
            ((LinearLayout) findViewById(R.id.main_fixmap)).addView(buttons[i]);
        }
    }

    private void playEnterAnimation(final Button button, int position) {

        /**
         * Animator that animates buttons x and y position simultaneously with size
         */
        AnimatorSet buttonAnimator = new AnimatorSet();

        /**
         * ValueAnimator to update x position of a button
         */
        ValueAnimator buttonAnimatorX = ValueAnimator.ofFloat(startPositionX + button.getLayoutParams().width / 2,
                pentagonVertices[position].x);
        buttonAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setX((float) animation.getAnimatedValue() - button.getLayoutParams().width / 2);
                button.requestLayout();
            }
        });
        buttonAnimatorX.setDuration(300);

        /**
         * ValueAnimator to update y position of a button
         */
        ValueAnimator buttonAnimatorY = ValueAnimator.ofFloat(startPositionY + 5,
                pentagonVertices[position].y);
        buttonAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setY((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorY.setDuration(300);

        /**
         * This will increase the size of button
         */
        ValueAnimator buttonSizeAnimator = ValueAnimator.ofInt(5, width);
        buttonSizeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.getLayoutParams().width = (int) animation.getAnimatedValue();
                button.getLayoutParams().height = (int) animation.getAnimatedValue();
                button.requestLayout();
            }
        });
        buttonSizeAnimator.setDuration(300);

        /**
         * Add both x and y position update animation in
         *  animator set
         */
        buttonAnimator.play(buttonAnimatorX).with(buttonAnimatorY).with(buttonSizeAnimator);
        buttonAnimator.setStartDelay(enterDelay[position]);
        buttonAnimator.start();
    }

    private void playExitAnimation(final Button button, int position) {

        /**
         * Animator that animates buttons x and y position simultaneously with size
         */
        AnimatorSet buttonAnimator = new AnimatorSet();

        /**
         * ValueAnimator to update x position of a button
         */
        ValueAnimator buttonAnimatorX = ValueAnimator.ofFloat(pentagonVertices[position].x - button.getLayoutParams().width / 2,
                startPositionX);
        buttonAnimatorX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setX((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorX.setDuration(300);

        /**
         * ValueAnimator to update y position of a button
         */
        ValueAnimator buttonAnimatorY = ValueAnimator.ofFloat(pentagonVertices[position].y,
                startPositionY + 5);
        buttonAnimatorY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setY((float) animation.getAnimatedValue());
                button.requestLayout();
            }
        });
        buttonAnimatorY.setDuration(300);

        /**
         * This will decrease the size of button
         */
        ValueAnimator buttonSizeAnimator = ValueAnimator.ofInt(width, 5);
        buttonSizeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.getLayoutParams().width = (int) animation.getAnimatedValue();
                button.getLayoutParams().height = (int) animation.getAnimatedValue();
                button.requestLayout();
            }
        });
        buttonSizeAnimator.setDuration(300);

        /**
         * Add both x and y position update animation in
         *  animator set
         */
        buttonAnimator.play(buttonAnimatorX).with(buttonAnimatorY).with(buttonSizeAnimator);
        buttonAnimator.setStartDelay(exitDelay[position]);
        buttonAnimator.start();
    }
}
